package users;

import java.io.Serializable;
import java.util.ArrayList;

import log_error.UserException;

import report.Appointment;

/**
 * This class is the abstract class that all users are extended from. It
 * contains a personal information object and requires an ID for it's children,
 * and has getters and setters for both the actual PersonalInfo object and has
 * chained getters and setters for all of the personalInfo attributes (the
 * getter for password).
 * 
 * @author mramsey3
 * 
 */
public abstract class User implements Serializable{

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    protected PersonalInfo personalInfo;
    
    protected ArrayList<Appointment> appointments = new ArrayList<Appointment>();

    public abstract int getId();

    /**
     * Getter for the boolean state of the account--stored within the
     * PersonalInfo object and accessed by chained getters.
     * 
     * @author mramsey3
     * @return boolean the state of the account.
     */
    public boolean isActive() {
	return personalInfo.isActive();
    }

    /**
     * Lowest level constructor for the instantiation of class, only requiring
     * the accessLevel to be stored in the PersonalInfo object.
     * 
     * @param accessLevel
     *            The accessLevel of the desired user--also the type of user.
     */
    public User(AccessLevel accessLevel) {
	personalInfo = new PersonalInfo(accessLevel);
    }

    /**
     * Middle level of constructor for the instantiation of class, requiring
     * some basic user info to be stored in the personalInfo object.
     * 
     * @param firstName
     *            The first name of desired user account.
     * @param lastName
     *            The last name of desired user account.
     * @param username
     *            The username of desired user account.
     * @param password
     *            The password of desired user account.
     * @param accessLevel
     *            The AccessLevel enum type of desired account.
     */
    public User(String firstName, String lastName, String username,
	    String password, AccessLevel accessLevel) {
	personalInfo = new PersonalInfo(firstName, lastName, username,
		password, accessLevel);
    }

    /**
     * The most discrete version of of the class instantiation. This constructor
     * requires all Attributes of the personalInfo object.
     * 
     * @param firstName
     *            The first name of desired user.
     * @param lastName
     *            The Last n name of desired user.
     * @param username
     *            The username of desired user.
     * @param password
     *            The password of desired user.
     * @param accessLevel
     *            The desired "type" of user.. AccessLevel enum type.
     * @param email
     *            The email of desired user.
     * @param cellPhone
     *            The cellPhone number of desired user.
     * @param age
     *            The age of desired user.
     * @param address
     *            the Address object of desired user. To be input using the
     *            address constructor.
     */
    public User(String firstName, String lastName, String username,
	    String password, AccessLevel accessLevel, String email,
	    int cellPhone, int age, Address address) {
	personalInfo = new PersonalInfo(firstName, lastName, username,
		password, accessLevel, email, cellPhone, age, address);
    }

    /**
     * The method to add an appointment to the users arraylist of appointments..
     * does not add duplicates.
     * 
     * @author mramsey3
     * @param appointment
     *            pointer to appointment to add.
     */
    public void addAppointment(Appointment appointment) {
	if (!appointments.contains(appointment)) {
	    appointments.add(appointment);
	}
    }

    /**
     * The method to remove an appointment from an arralList of appointments..
     * does not try to remove an appointment that is not there.
     * 
     * @author mramsey3
     * @param appointment
     *            pointer to appointment to remove from user arrayList.
     */
    public void removeAppointment(Appointment appointment) {
	if (appointments.contains(appointment)) {
	    appointments.remove(appointment);
	}
    }

    /**
     * The getter for the actual PersonalInfo object.
     * 
     * @author mramsey3
     * @return The personalInfo object desired.
     */
    public PersonalInfo getPersonalInfo() {
	return personalInfo;
    }

    /**
     * The setter for the actual PersonalInfo object.
     * 
     * @author mramsey3
     * @param personalInfo
     *            The personalInfo object to set.
     */
    public void setPersonalInfo(PersonalInfo personalInfo) {
	this.personalInfo = personalInfo;
    }

    /**
     * Getter for the attribute, firstName of the personalInfo object.
     * 
     * @author mramsey3
     * @return String firstName.
     */
    public String getFirstName() {
	return personalInfo.getFirstName();
    }

    /**
     * Getter for the attribute, lastName, of the personalInfo object.
     * 
     * @author mramsey3
     * @return String lastName
     */
    public String getLastName() {
	return personalInfo.getLastName();
    }

    /**
     * Getter for the attribute, username, of the personalInfo object.
     * 
     * @author mramsey3
     * @return String the username.
     */
    public String getUsername() {
	return personalInfo.getUsername();
    }

    /**
     * Getter for the attribute, email, of the personalInfo object.
     * 
     * @author mramsey3
     * @return String the email.
     */
    public String getEmail() {
	return personalInfo.getEmail();
    }

    /**
     * Getter for the attribute, cellPhone, of the personalInfo object.
     * 
     * @author mramsey3
     * @return int the cellPhone number.
     */
    public int getCellPhone() {
	return personalInfo.getCellPhone();
    }

    /**
     * Getter for the attribute, age of the personalInfo object.
     * 
     * @author mramsey3
     * @return int the age.
     */
    public int getAge() {
	return personalInfo.getAge();
    }

    /**
     * Getter for the attribute, accessLevel of the personalInfo object.
     * 
     * @author mramsey3
     * @return AccessLevel the user accessLevel.
     */
    public AccessLevel getAccessLevel() {
	return personalInfo.getAccessLevel();
    }

    /**
     * Getter for the Address object attribute, address of the personalInfo
     * object.
     * 
     * @author mramsey3
     * @return Address the address object of the user.
     */
    public Address getAddress() {
	return personalInfo.getAddress();
    }

    /**
     * Getter for the String version of the Address object, address, of the
     * personalInfo object.
     * 
     * @author mramsey3
     * @return String the 2 line address of the user.
     */
    public String getAddressString() {
	return personalInfo.getAddressString();
    }

    /**
     * Setter for the attribute, firstName, of the personalInfo object.
     * 
     * @author mramsey3
     * @param firstName
     *            the First name to set.
     */
    public void setFirstName(String firstName) {
	personalInfo.setFirstName(firstName);
    }

    /**
     * Setter for the attribute, lastName, of the personalInfo object.
     * 
     * @author mramsey3
     * @param lastName
     *            the Last name to set.
     */
    public void setLastName(String lastName) {
	personalInfo.setLastName(lastName);
    }

    /**
     * Setter for the attribute, username, of the personalInfo object.
     * 
     * @author mramsey3
     * @param username
     *            the username to set.
     */
    public void setUsername(String username) {
	personalInfo.setUsername(username);
    }

    /**
     * Setter for the attribute, password, of the personalInfo object.
     * 
     * @author mramsey3
     * @param password
     *            the password to set.
     */
    public void setPassword(String password) {
	personalInfo.setPassword(password);
    }

    /**
     * Setter for the attribute, email, of the personalInfo object.
     * 
     * @author mramsey3
     * @param email
     *            the email to set.
     */
    public void setEmail(String email) {
	personalInfo.setEmail(email);
    }

    /**
     * Setter for the attribute, cellPhone, of the personalInfo object.
     * 
     * @author mramsey3
     * @param cellPhone
     *            the cellPhone number to set.
     */
    public void setCellPhone(int cellPhone) {
	personalInfo.setCellPhone(cellPhone);
    }

    /**
     * Setter for the attribute, age, of the personalInfo object.
     * 
     * @author mramsey3
     * @param age
     *            the age to set.
     */
    public void setAge(int age) {
	personalInfo.setAge(age);
    }

    /**
     * Setter for the attribute, accessLevel, of the personalInfo object.
     * 
     * @author mramsey3
     * @param accessLevel
     *            the accessLevel to set.
     */
    public void setAccessLevel(AccessLevel accessLevel) {
	personalInfo.setAccessLevel(accessLevel);
    }

    /**
     * Setter for the attribute, address, of the personalInfo object.
     * 
     * @author mramsey3
     * @param address
     *            the address to set.
     */
    public void setAddress(Address address) {
	personalInfo.setAddress(address);
    }

    public boolean checkPassword(String password) throws UserException {
	return personalInfo.checkPassword(password);
    }

    public void resetAttempts() {
	personalInfo.resetAttempts();
    }

    public void deactivate() {
	personalInfo.deactivate();
    }

    public void activate() {
	personalInfo.activate();
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Object#equals(java.lang.Object) Overridden equals object
     * to be used with the userList.
     */
    public boolean equals(Object obj) {
	User temp = (User) obj;
	return ((temp.personalInfo.getFirstName().equals(this.personalInfo
		.getFirstName()))
		&& (temp.personalInfo.getLastName().equals(this.personalInfo
			.getLastName())) && (temp.personalInfo.getUsername()
		.equals(this.personalInfo.getUsername())));
    }

    /**
     * @author Chris Bayruns
     * @return The arraylist of appointments
     */
    public ArrayList<Appointment> getAppointments() {
	ArrayList<Appointment> result = new ArrayList<Appointment>();

	for (Appointment i : this.appointments) {
	    result.add(i.clone());
	}
	return result;
    }
}
